package ConexaoDados;


import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafish.clients.opc.JEasyOpc;
import javafish.clients.opc.JOpc;
import javafish.clients.opc.component.OpcGroup;
import javafish.clients.opc.component.OpcItem;
import javafish.clients.opc.exception.*;

/**
 *
 * @author Igor
 */
public class LeituraOPCThread {

//Declaração de Variaveis.    
    
private List listTags;    
private String grupos;
private String nomeServidor;    
private int tempo;
private int tempoTotal;
private BufferedReader csvBanco = null;
private boolean flagParada = false;
private HistoriadorMalhaJpaController DaoHistoriador = new HistoriadorMalhaJpaController("ProjetoCA_-_IgorPU");
private HistoriadorMalha historiador;
private List<VariaveisOPC> List_variaveisopc;

//Comandos para captar a data na forma padrão conhecida, dia mes ano, hora minuto e segundo, fazemos isso porque se utilizassemos a hora normal ela viria com gmt, timezone, etc.
SimpleDateFormat fdS = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
Date data_atual = null;
String data_atual_temp;
//Fim da declaração de variaveis.

//Função de conexão ao servidos OPC, nela é passado como parametro: "Lista de tags a ser lida, normalmente seria a lista de tags do servidor", Tempoloop, TempoTotal, e por ultimo o Grupo que essas tags pertecem que seria o Nó do servidor.
    public void conectar(List ListTags, String NomeServidor, int TempoLoop, int TempoTotal, String Grupo) throws IOException{

        try {
            Thread.sleep(100);
        } catch (InterruptedException ex) {
            Logger.getLogger(LeituraOPCThread.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        this.listTags = ListTags;
        this.nomeServidor = NomeServidor;
        this.tempo = TempoLoop;
        this.tempoTotal = TempoTotal;
        this.grupos = Grupo;
        //Criação de uma lista de variaveis opc de determinado servidor, ela servirá mais na frente para sabermos que determinada tag lida é igual a tag adicionada no banco de dados com seu respectivo servidor e malha.
        List_variaveisopc = consultasql_opc.ConsultarVariaveisDeServidor(nomeServidor);
        //Inicialização do JOPC.
        JOpc.coInitialize();
        //Chamada da conexão, é passado como parametro o endereço do servidor"Localhost", o Nome do servidor e por ultimo seu numero de conexão o qual está sendo gerado randomicamente.
        final JEasyOpc opc = new JEasyOpc("localhost", nomeServidor, "JOPC1"+Math.random());
        //Registrando o grupo.
        final OpcGroup grupo = new OpcGroup(grupos, true, 100, 0.0f);
        //For para registrar todas as tags da lista que foi passada para o grupo.
        for (int i = 0 ; i < listTags.size() ; i++){   
            final OpcItem item = new OpcItem(listTags.get(i).toString().trim(), true, "");
            grupo.addItem(item);            
        }
        //Adiciona o grupo ao OPC.        
        opc.addGroup( grupo );    
        
        
        //Inicia a thread.
        Thread a = new Thread() {            
            @Override
            
            public void run() {
                                                       
            try {
                opc.connect();
            } catch (ConnectivityException ex) {
                Logger.getLogger(LeituraOPCThread.class.getName()).log(Level.SEVERE, null, ex);
            }
            try {
                opc.registerGroups();
            } catch (UnableAddGroupException ex) {
                Logger.getLogger(LeituraOPCThread.class.getName()).log(Level.SEVERE, null, ex);
            } catch (UnableAddItemException ex) {
                Logger.getLogger(LeituraOPCThread.class.getName()).log(Level.SEVERE, null, ex);
            }
            
            opc.start(); 
            
            //Variaveis de controle da thread por tempo, depois de 4 minutos a thread encerra e começa a gravar novos valores, NOTE: Está em minutos, se quiser em horas é só descer até a ultima linha do programa e editar a linha "mm" com "hh".
            int tempoConclusao = Integer.parseInt(getDateTime())+tempoTotal;
            int tempoReal = Integer.parseInt(getDateTime());
            
            //Try que cria um arquivo CSV com nome igual ao nome do servidor e seu grupo.
            try {
                FileWriter writer = new FileWriter("c:\\"+nomeServidor+"---"+grupos+".csv", false);
            } catch (IOException ex) {
                Logger.getLogger(LeituraOPCThread.class.getName()).log(Level.SEVERE, null, ex);
            }
            
            //While que funciona tanto para tempo quanto para uma parada de uma desconexão.   
            while(tempoConclusao >= tempoReal && flagParada == false) {
                tempoReal = Integer.parseInt(getDateTime());
                if(tempoConclusao<= tempoReal){
                    flagParada = true;
                }
                
                OpcGroup response = null;
                //Try para leitura das tags, ela é lida de forma sincrona e pelo grupo, é lida todas as tags do grupo de uma só vez.
                try {
                    response = opc.synchReadGroup(grupo);
                } catch (ComponentNotFoundException ex) {
                    Logger.getLogger(LeituraOPCThread.class.getName()).log(Level.SEVERE, null, ex);
                } catch (SynchReadException ex) {
                    Logger.getLogger(LeituraOPCThread.class.getName()).log(Level.SEVERE, null, ex);
                }
                //Try de parada, é aqui onde entra o tempo de loop, é o tempo de cada amostra.
                try {
                    sleep(tempo);
                } catch (InterruptedException ex) {
                    Logger.getLogger(LeituraOPCThread.class.getName()).log(Level.SEVERE, null, ex);
                }                
                
                try
                {
                    //Try que cria um arquivo CSV com nome igual ao nome do servidor e seu grupo, diferente do de cima por causa do "TRUE", neste caso ele não se encerra quando começa a criar novamente, um serve para criar do zero e este serve para criar mantendo o existente.
                    FileWriter writer = new FileWriter("c:\\"+nomeServidor+"---"+grupos+".csv", true);
                    //for que percorre todo response pegando o valor das tags já lidas acima.
                    for(int i = 0 ; i < response.getItems().size() ; i++){
                                              
                        //Tratamento da String que vem do servidor OPC.
                        String valor = response.getItems().get(i).toString().trim();                        
                        String [] array = valor.split(";");                        
  
                        //Escrita no CSV.
                        writer.append(array[2].trim()+";"+array[6].trim()+";"+array[5].trim());
                        writer.append('\r');
                        writer.append('\n');
                    }
                    writer.flush();
                    writer.close();
                }
                catch(IOException e)
                {
                    e.printStackTrace();
                } 
            }//FIM DO LAÇO WHILE DE AQUISIÇÃO DE DADOS, DAQUI PRA FRENTE É SÓ A LEITURA DO CSV PARA PERSISTENCIA NO BANCO. - Futuramente essa área abaixo será implementada em Threads.

                data_atual_temp = fdS.format(new Date());
                
                try {
                data_atual = fdS.parse(data_atual_temp);
                } catch (ParseException ex) {
                Logger.getLogger(LeituraThread.class.getName()).log(Level.SEVERE, null, ex);
                }                 
                
                String linha = "";
                
                while(linha!=null){
                try {
                    linha = csvBanco.readLine();                  
                } catch (IOException ex) {
                    Logger.getLogger(TelaArvores_Administrador.class.getName()).log(Level.SEVERE, null, ex);
                }
                    
                    if(linha!=null){
                        
                        String [] valorTags = linha.split(";");                        
                        String [] valorTagsNOME = valorTags[0].split(" ");
                        String [] valorTagsVALOR = valorTags[1].split(" ");                        
                        String [] valorTagsHora = valorTags[2].split(" ");                        
                        SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
                        
                        Date d = null;
                        try {
                            d = df.parse(valorTagsHora[5]);
                        } catch (ParseException ex) {
                            Logger.getLogger(LeituraThread.class.getName()).log(Level.SEVERE, null, ex);
                        }
                        
                        //for para detectar qual tag pertence aquela tag já cadastrada no servidor.
                        for(int i = 0 ; i < List_variaveisopc.size() ; i++){
                            
                            if(valorTagsNOME[2].trim().equals(List_variaveisopc.get(i).getNome().trim())){
                                
                                Double value = Double.parseDouble(valorTagsVALOR[2]);                                                                                                 
                                historiador = new HistoriadorMalha(data_atual, List_variaveisopc.get(i).getMalha_fk(), List_variaveisopc.get(i).getTipo().trim(), value, List_variaveisopc.get(i).getServidor_fk(), d);                                
                                DaoHistoriador.create(historiador);      
                                }                        
                            }
                 
                        
                   
                    }                                        
                }
                
            
            //Terminando a conexão OPC.
            opc.terminate();
            try {
                sleep(1);
            } catch (InterruptedException ex) {
                Logger.getLogger(LeituraOPCThread.class.getName()).log(Level.SEVERE, null, ex);
            }           
            }
    };   
    
        a.start();
            
         
        JOpc.coUninitialize(); 
            
    }     
    
    //Função para pegar tempo real, está em minutos para agilizar e ver o resultado logo mas pode ser trocado para hora conforme combinado, é só modificar o "mm" por "hh".
    private String getDateTime() {
        DateFormat dateFormat = new SimpleDateFormat("mm");
        Date date = new Date();
        return dateFormat.format(date);
}
    
    //Função de parada da Thread, caso o botão de desconexão seja pressionado.
    public void pararThread(){
        flagParada = true;        
    }
}